﻿using System;
using System.Collections.Generic;
using System.Net.Mqtt;
using System.Net.Mqtt.Sdk;
using System.Text;
using System.Threading.Tasks;
using log4net;
using Newtonsoft.Json;

namespace AutoAllocService.Messaging
{
    public class MqttHelper
    {
        private static MqttHelper _instance;
        public static MqttHelper Instance => _instance ?? new MqttHelper();

        private readonly MqttClientFactory _factory;
        private readonly ILog _log = LogManager.GetLogger(typeof(MqttHelper));
        private readonly IMqttClient _client;
        private readonly MqttHandler _handler;

        public MqttHelper()
        {
            _factory = new MqttClientFactory(Program.AppSetting.Mqtt.Host);
            _client = _factory.CreateClientAsync(new MqttConfiguration
            {
                Port = Program.AppSetting.Mqtt.Port
            }).Result;

            _handler = new MqttHandler(_client);
        }

        public async System.Threading.Tasks.Task Run()
        {
            _client.MessageStream.Subscribe(OnMessage);
            var credentials = new MqttClientCredentials(Program.AppSetting.Mqtt.ClientId);
            _client.Disconnected += (s, e) =>
            {
                _log.Warn(e);
                _client.ConnectAsync(credentials);
            };
            await _client.ConnectAsync(credentials);
            await _client.SubscribeAsync("/CD/TH/Driver", MqttQualityOfService.AtLeastOnce);
        }

        public async System.Threading.Tasks.Task PublishAsync(string topic, string message)
        {
            var bytes = Encoding.UTF8.GetBytes(message);
            await _client.PublishAsync(new MqttApplicationMessage(topic, bytes), MqttQualityOfService.AtLeastOnce);
        }

        public async System.Threading.Tasks.Task PublishAsync<T>(string topic, T payload)
        {
            var message = JsonConvert.SerializeObject(payload);
            var bytes = Encoding.UTF8.GetBytes(message);
            await _client.PublishAsync(new MqttApplicationMessage(topic, bytes), MqttQualityOfService.AtLeastOnce);
        }

        private void OnMessage(MqttApplicationMessage message)
        {
            _log.Info(message.Payload);
            try
            {
                _handler.DealMessages(message);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                _log.Error(e);
            }
        }
    }
}
